package com.tsystems.train.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotNull;

import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import com.tsystems.train.entity.Station;
import com.tsystems.train.entity.TimeTableElement;
import com.tsystems.train.entity.Train;
import com.tsystems.train.service.StationServices;
import com.tsystems.train.service.TicketServices;
import com.tsystems.train.service.TimeTableElementServices;
import com.tsystems.train.service.TrainServices;

@Named("buyTicketBean")
@SessionScoped
public class BuyTicketBean implements Serializable {

	private static final long serialVersionUID = 2165793273424547096L;

	@EJB
	private TimeTableElementServices tteService;

	@EJB
	private TrainServices trainService;

	@EJB
	private StationServices stationService;

	@EJB
	private TicketServices ticketService;

	@Inject
	private UserBean user;

	private Train keyTrain;

	private List<Station> stations;

	@NotNull(message = "Arrival station is requied")
	private Station arrivalStation;

	@NotNull(message = "Departure station is requied")
	private Station departureStation;

	@NotNull(message = "Arrival time is requied")
	@Future(message = "Arrival time must be in future")
	private Date arrivalTime;

	@NotNull(message = "Departure time is requied")
	@Future(message = "Departure time must be in future")
	private Date departureTime;

	private HashMap<Train, List<TimeTableElement>> result;

	private TreeNode root;

	private TreeNode selectedNode;

	public BuyTicketBean() {

		keyTrain = new Train("", 0);
		stations = new ArrayList<Station>();
		arrivalStation = new Station("");
		departureStation = new Station("");
		result = new HashMap<Train, List<TimeTableElement>>();

		selectedNode = new DefaultTreeNode();

	}

	@PostConstruct
	public void init() {
		root = new DefaultTreeNode("root", null);
		StationConverter.stations = stationService.viewStations();
		stations = StationConverter.stations;

	}

	public String findTrain() {
		result = tteService.findTrain(departureStation, arrivalStation,
				departureTime, arrivalTime);
		if (result.keySet().isEmpty()) {
			FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
					0 + " trains found", null);

			FacesContext.getCurrentInstance().addMessage(null, message);
			return null;
		}
		if (!result.isEmpty()) {
			root = new DefaultTreeNode("root", null);

			Set<Train> trains = result.keySet();
			FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
					trains.size() + " trains found", null);
			FacesContext.getCurrentInstance().addMessage(null, message);
			for (Train train : trains) {

				List<TimeTableElement> tte = result.get(train);
				if (tte.size() == 1) {
					TimeTableElement first = tte.get(0);
					PathNode node = new PathNode(train, first
							.getDepartureStation().getName(),
							first.getDepartureTime(), first.getArrivalStation()
									.getName(), first.getArrivalTime());

					new DefaultTreeNode(node, root);
				} else {
					TimeTableElement first = tte.get(0);
					TimeTableElement finish = tte.get(tte.size() - 1);
					PathNode node = new PathNode(train, first
							.getDepartureStation().getName(),
							first.getDepartureTime(), finish
									.getArrivalStation().getName(),
							finish.getArrivalTime());

					TreeNode tr = new DefaultTreeNode(node, root);

					for (TimeTableElement element : tte) {

						new DefaultTreeNode(new PathNode(train, element), tr);
					}
				}

			}
		}

		return null;
	}

	public List<Station> getStations() {
		return stations;
	}

	public void setStations(List<Station> stations) {
		this.stations = stations;
	}

	public Station getArrivalStation() {
		return arrivalStation;
	}

	public void setArrivalStation(Station arrivalStation) {
		this.arrivalStation = arrivalStation;
	}

	public Station getDepartureStation() {
		return departureStation;
	}

	public void setDepartureStation(Station departureStation) {
		this.departureStation = departureStation;
	}

	public Date getArrivalTime() {
		return arrivalTime;
	}

	public void setArrivalTime(Date arrivalTime) {
		this.arrivalTime = arrivalTime;
	}

	public Date getDepartureTime() {
		return departureTime;
	}

	public void setDepartureTime(Date departureTime) {
		this.departureTime = departureTime;
	}

	public Train getKeyTrain() {
		return keyTrain;
	}

	public void setKeyTrain(Train keyTrain) {
		this.keyTrain = keyTrain;
	}

	public TreeNode getRoot() {

		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}

	public TreeNode getSelectedNode() {
		return selectedNode;
	}

	public void setSelectedNode(TreeNode selectedNode) {
		this.selectedNode = selectedNode;
	}

	public String buyTicket() {
		if (selectedNode != null && selectedNode.getData() instanceof PathNode) {
			PathNode data = (PathNode) selectedNode.getData();
			if (data.getTrain() != null) {
				if (data.getTte() == null) {

					List<TimeTableElement> elements = result.get(data
							.getTrain());
					String result = ticketService.buyTicket(elements.get(0)
							.getDepartureStation(),
							elements.get(elements.size() - 1)
									.getArrivalStation(), elements.get(0)
									.getDepartureTime(), elements.get(0)
									.getTrain(),
							elements.get(elements.size() - 1).getArrivalTime(),
							user.getLogin());

					FacesMessage message = new FacesMessage(
							FacesMessage.SEVERITY_INFO, "Info", result);
					FacesContext.getCurrentInstance().addMessage(null, message);
				} else {
					String result = ticketService.buyTicket(data.getTte()
							.getDepartureStation(), data.getTte()
							.getArrivalStation(), data.getTte()
							.getDepartureTime(), data.getTrain(), data.getTte()
							.getArrivalTime(), user.getLogin());
					FacesMessage message = new FacesMessage(
							FacesMessage.SEVERITY_ERROR, "Buy error", result);
					FacesContext.getCurrentInstance().addMessage(null, message);

				}
			}
		} else {
			FacesMessage message = new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "Buy error",
					"Please select train or single trace in table.");
			FacesContext.getCurrentInstance().addMessage(null, message);
		}
		return null;
	}
}
